section .data
    sysWrite:   equ 1
    stdOut:     equ 1
    sysExit:    equ 60
    exitCode:   equ 0
    asciiZero:  equ 48
    
    newLine:    db  0xa
    wrongArgc:  db  "Must be two command line argument", 0xa
    
section .text
    global _start
    
_start:
    pop rcx                             ; rcx - argc
    
    ;;
    ;; Check argc
    ;;
    cmp rcx, 3
    jne argcError
    
    ;;
    ;; Start to sum arguments
    ;;
    
    add rsp, 8                          ; skip argv[0] - program name
    
    pop rsi                             ; get argv[1]
    call strToInt                       ; convert argv[1] string to int
    mov r10, rax                        ; put first number to r10    
    pop rsi                             ; get argv[2]
    call strToInt                       ; convert argv[2] string to int
    mov r11, rax                        ; put second number to r11
    add r10, r11                        ; get sum of them
    
    ;;
    ;; Convert to string
    ;;
    mov rax, r10
    xor r12, r12                        ; number counter
    jmp intToStr                        ; convert to string
    
;;
;; Print argc error
;;
argcError:
    mov rax, sysWrite                   ; sysWrite system call
    mov rdi, stdOut                     ; first argument: stdandard output
    mov rsi, wrongArgc                  ; second argument: msg memory address
    mov rdx, 34                         ; third argument: length of msg
    syscall                             ; call write syscall
    jmp exit                            ; exit from program
    
;;
;; Convert int to string
;;
intToStr:
    mov rdx, 0                          ; reminder from division
    mov rbx, 10                         ; base
    div rbx                             ; rax: quotient, rdx: reminder
    add rdx, asciiZero                  ; add '\0'
    ;add rdx, 0x0
    push rdx                            ; push reminder to stack
    inc r12                             ; go next
    cmp rax, 0                          ; check factor with 0
    jne intToStr                        ; loop again
    jmp print                           ; print result
    
;;
;; Convert string to int
;; 使用秦九韶算法来处理多项式分解
strToInt:
    xor rax, rax                        ; accumulator
    mov rcx, 10                         ; base for multiplication
next:
    cmp [rsi], byte 0                   ; check that it is end of string
    je returnStr                        ; return int
    mov bl, [rsi]                       ; mov current char to bl
    sub bl, asciiZero                   ; get number
    mul rcx                             ; rax = rax * rcx
    add rax, rbx                        ; rax = rax + rbx(digit)
    inc rsi                             ; get next char memory address
    jmp next                            ; loop again
    
returnStr:
    ret
    
;;
;; Print number
;;
print:
    ;; Calculate number length
    mov rax, 1
    mul r12
    mov r12, 8                          ; a number occupy 8 bytes
    mul r12                             ; rax: stands for all occupied bytes
    mov rdx, rax                        ; third argument: the buf's length
    ;;
    
    ;; Print sum
    mov rax, sysWrite
    mov rdi, stdOut
    mov rsi, rsp
    syscall
    ;;
    
    ;; Newline
    jmp printNewLine
    
;;
;; Print a new line
;;
printNewLine:
    mov rax, sysWrite                   ; write syscall
    mov rdi, stdOut                     ; first argument: stdandard output
    mov rsi, newLine                    ; second argument: buf address
    mov rdx, 1                          ; third argument: length of buf
    syscall
    jmp exit
    
;;
;; Exit from program
;;
exit:
    mov rax, sysExit                    ; exit syscall
    mov rdi, exitCode                   ; exit code
    syscall                             ; call exit syscall
